// File resource manager
// Copyright 2005 (C) Ralph Thomas

#include <util/resources.h>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/fstream.hpp>
#include <adobe/adam_evaluate.hpp>
#include <adobe/adam_parser.hpp>

namespace bfs = boost::filesystem;

namespace util {
	boost::filesystem::path getResourcePath() {
		return getMissionPath();
	}
	boost::filesystem::path getResource( const std::string& mimetype,
		const std::string& res ) {
		//
		// Currently we assume that all resources are stored in
		// ./resources. This will have to change eventually.
		//
		bfs::path base( getResourcePath() );
		bfs::path path( base / bfs::path( mimetype, bfs::native ) );
		//
		// See if the file exists here (in resources/mime/type)
		// and work our way up if it doesn't.
		//
		bfs::path file( path / res );
		if( bfs::exists( file ) ) return file;
		//
		// See if the file exists at resources/mime.
		//
		path = path.branch_path();
		file = path / res;
		if( bfs::exists( file ) ) return file;
		//
		// Finally check resources/.
		//
		file = base / res;
		if( bfs::exists( file ) ) return file;
		bfs::path relative( bfs::path( mimetype, bfs::native ) / bfs::path( res, bfs::native ) );
		throw std::runtime_error( "Unable to load resource: " + relative.native_file_string() );
	}
	adobe::sheet_t* getSheet( const std::string& mimetype, const std::string& url ) {
		//
		// Find out the path of the sheet.
		//
		bfs::path path( getResource( mimetype, "adam" ) );
		if( path.empty() ) return 0;
		bfs::ifstream ifs( path );
		//
		// Create the sheet for this ifstream.
		//
		adobe::sheet_t* sheet( new adobe::sheet_t() );
		//
		// Read the sheet in from the file stream.
		//
		try {
			adobe::parse( ifs,
				adobe::line_position_t( path.string().c_str() ),
				adobe::bind_to_sheet( *sheet ) );
		} catch( ... ) {
			//
			// Something didn't work; clean up and rethrow.
			//
			delete sheet;
			throw;
		}
		//
		// Set the sheet's URL to point to the specified URL/model.
		// We need to touch and set because it seems like set isn't
		// triggering a touch on it's own.
		//
		adobe::name_t model_url( "model_url" );
		sheet->update();
		sheet->touch( &model_url, (&model_url)+1 );
		sheet->set( model_url, adobe::any_regular_t( url ) );
		sheet->update();
		return sheet;
	}
};

